import router from './router'
import store from './store'
import NProgress from 'nprogress' // progress bar
import notification from 'ant-design-vue/es/notification'
import { getAccessToken } from '@/utils/tokenUtils/accessTokenCache'

NProgress.configure({ showSpinner: false }) // NProgress Configuration


const allowList = ['login', 'register', 'registerResult'] // no redirect allowList
const loginRoutePath = '/login'
const defaultRoutePath = '/home'

/**
 * to: Route: 即将要进入的目标 路由对象
 * from: Route: 当前导航正要离开的路由
 * next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数
 * next(): 进行管道中的下一个钩子。如果全部钩子执行完了，则导航的状态就是 confirmed (确认的)。
 * next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮)，那么 URL 地址会重置到 from 路由对应的地址
 * next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断，然后进行一个新的导航。你可以向 next 传递任意位置对象，且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项
 * next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例，则导航会被终止且该错误会被传递给 router.onError() 注册过的回调
 * 确保要调用 next 方法，否则钩子就不会被 resolved
 */
router.beforeEach((to, from, next) => { 
  NProgress.start()
  // 获取token
  let token = getAccessToken(); 
  // token存在
  if (token) {
    if (to.path === loginRoutePath) {
      next({ path: defaultRoutePath })
      NProgress.done()
    } else { 
      if (store.getters.roles.length === 0) {
        store.dispatch('getUserInfo').then(res => {
          const roles = res.data && res.data.role
          // generate dynamic router
          store.dispatch('generateRoutes', { roles }).then(() => {
            // 根据roles权限生成可访问的路由表
            // 动态添加可访问路由表
            // console.log(store.getters.addRouters)

            // router.addRoutes(store.getters.addRouters) 
            for (let x of store.getters.addRouters) {
              router.addRoute(x)
            }
            // 请求带有 redirect 重定向时，登录自动重定向到该地址
            const redirect = decodeURIComponent(from.query.redirect || to.path)
            if (to.path === redirect) {
              next({ ...to, replace: true }) // set the replace: true so the navigation will not leave a history record
            } else {
              // 跳转到目的路由
              next({ path: redirect })
            }
          })
        })
          .catch((error) => {
            // notification.error({
            //   message: '错误',
            //   description: '请求用户信息失败，请重试:' + error
            // })
            // 失败时，获取用户信息失败时，调用登出，来清空历史保留信息
            store.dispatch('logout').then(() => {
              next({ path: loginRoutePath, query: { redirect: to.fullPath } })
            })
          })
      } else {
        next()
      }
    }
  } else {
    if (allowList.includes(to.name)) {
      // 在免登录名单，直接进入
      next()
    } else {
      // 跳转到登录界面
      next({ path: loginRoutePath, query: { redirect: to.fullPath } })
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

// 解决Loading chunk (\d)+ failed问题
router.onError((error) => {
  const pattern = /Loading chunk (\d)+ failed/g;
  const isChunkLoadFailed = error.message.match(pattern);
  if (isChunkLoadFailed) {
    // 用路由的replace方法，并没有相当于F5刷新页面，失败的js文件并没有从新请求，会导致一直尝试replace页面导致死循环，
    // const targetPath = router.history.pending.fullPath;
    // router.replace(targetPath);
    // 而用 location.reload 方法，相当于触发F5刷新页面，虽然用户体验上来说会有刷新加载察觉，但不会导致页面卡死及死循环
    location.reload();
  }
});